package com.chenl.provider.DEMOS.多线程相关;

import com.chenl.provider.DEMOS.日志相关.全链路日志以及Spring线程池装饰器的使用.MdcTaskDecorator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolTaskExcutor implements AsyncConfigurer {
    /**
     * 如果需要多个线程池，不同的业务使用不同的线程池，那么只需要在这里配置多个线程池即可，名字区分开即可。
     * 可以配合@Async使用
     * @return
     */

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(50);
        //设置最大线程数
        executor.setMaxPoolSize(500);
        //线程池所使用的缓冲队列
        executor.setQueueCapacity(800);
        //等待任务在关机时完成--表明等待所有线程执行完
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //等待时间（默认为0，此时立即停止），并没等待xx秒后强制停止
        executor.setAwaitTerminationSeconds(60);
        //设置线程空闲时间
        executor.setKeepAliveSeconds(300);
        //线程名称前缀
        executor.setThreadNamePrefix("TaskExecutor--");
        /**
         * 拒绝任务处理器
         * CallerRunsPolicy():交由调用方线程运行,比如main线程
         * AbortPolicy():直接抛出异常
         * DiscardPolicy():直接丢弃
         * DIscardOldestPolicy():丢弃队列中最老的任务
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setTaskDecorator(new MdcTaskDecorator());
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }

    class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
            log.error("Async throw Exception \nAsync Method name -:[{}] ;\nAsync Parameter values -:{} ;\nAsync Exception message-:[{}] ;\nAsync Exception Detail:\n{}",method.getName()
                    ,Arrays.toString(obj), throwable.getMessage()+"_"+throwable.getCause(),throwable.getStackTrace());
        }
    }
}
